﻿using System;
using System.ComponentModel;
using System.Xml.Serialization;
using Microsoft.WowAddonStudio.FrameXml.Serialization.Attributes;
using Microsoft.WowAddonStudio.FrameXml.Serialization.Enumerations;

namespace Microsoft.WowAddonStudio.FrameXml.Serialization.LayoutFrames
{
    [Serializable]
    [DesignerCategory("code")]
    [XmlType(Namespace = "http://www.blizzard.com/wow/ui/")]
    [XmlRoot(Namespace = "http://www.blizzard.com/wow/ui/", IsNullable = false)]
    public class Button : Frame, IPropertyValidator
    {
        /// <summary>
        /// Gets or sets the text of the button.
        /// </summary>
        [XmlAttribute("text")]
        [Category("Appearance")]
        [Description("Used to define text to show on buttons.")]
        public string Text
        {
            get { return Properties.GetValue<string>("Text"); }
            set { Properties.SetValue("Text", value); }
        }

        /// <summary>
        /// Gets or sets the texture used for the button by default.
        /// </summary>
        [XmlElement]
        [Texture(FileType.Image)]
        [Category("Appearance")]
        [Description("Change the texture to this when button is in normal state.")]
        public Texture NormalTexture
        {
            get { return Properties.GetValue<Texture>("NormalTexture"); }
            set { Properties.SetValue("NormalTexture", value); }
        }

        /// <summary>
        /// Gets or sets the texture used for the button when pushed.
        /// </summary>
        [XmlElement]
        [Texture(FileType.Image)]
        [Category("Appearance")]
        [Description("Change the texture to this when clicked (and held). The texture changes back to its texture when the mouse button is released.")]
        public Texture PushedTexture
        {
            get { return Properties.GetValue<Texture>("PushedTexture"); }
            set { Properties.SetValue("PushedTexture", value); }
        }

        /// <summary>
        /// Gets or sets the texture used for the button when disabled.
        /// </summary>
        [XmlElement]
        [Texture(FileType.Image)]
        [Category("Appearance")]
        [Description("Define the texture to use when a button is disabled.")]
        public Texture DisabledTexture
        {
            get { return Properties.GetValue<Texture>("DisabledTexture"); }
            set { Properties.SetValue("DisabledTexture", value); }
        }

        /// <summary>
        /// Gets or sets the texture used for the button when highlighted.
        /// </summary>
        [XmlElement]
        [Texture(FileType.Image)]
        [Category("Appearance")]
        [Description("The texture used for the button when highlighted.")]
        public Texture HighlightTexture
        {
            get { return Properties.GetValue<Texture>("HighlightTexture"); }
            set { Properties.SetValue("HighlightTexture", value); }
        }

        /// <summary>
        /// Gets or sets the fontstring used for the button's text.
        /// </summary>
        [XmlElement]
        [Category("Appearance")]
        [Description("Used to define text to show on buttons.")]
        public FontString ButtonText
        {
            get { return Properties.GetValue<FontString>("ButtonText"); }
            set { Properties.SetValue("ButtonText", value); }
        }

        /// <summary>
        /// Gets or sets the font used for the button by default.
        /// </summary>
        [XmlElement]
        [Category("Appearance")]
        [Description("Define the font to use when a button is in normal state.")]
        [InheritsList(InheritableObjectType = typeof(Font))]
        public ButtonStyle NormalFont
        {
            get { return Properties.GetValue<ButtonStyle>("NormalFont"); }
            set { Properties.SetValue("NormalFont", value); }
        }

        /// <summary>
        /// Gets or sets the font used for the button when highlighted.
        /// </summary>
        [XmlElement]
        [Category("Appearance")]
        [Description("The font used for the button when highlighted.")]
        [InheritsList(InheritableObjectType = typeof(Font))]
        public ButtonStyle HighlightFont
        {
            get { return Properties.GetValue<ButtonStyle>("HighlightFont"); }
            set { Properties.SetValue("HighlightFont", value); }
        }

        /// <summary>
        /// Gets or sets the font used for the button when disabled.
        /// </summary>
        [XmlElement]
        [Category("Appearance")]
        [Description("Define the font to use when a button is disabled.")]
        [InheritsList(InheritableObjectType = typeof(Font))]
        public ButtonStyle DisabledFont
        {
            get { return Properties.GetValue<ButtonStyle>("DisabledFont"); }
            set { Properties.SetValue("DisabledFont", value); }
        }

        /// <summary>
        /// Gets or sets the color used for the button by default.
        /// </summary>
        [XmlElement]
        [Category("Appearance")]
        [EditorBrowsable]
        [Description("Define the color used for the button by default.")]
        [Color]
        public Color NormalColor
        {
            get { return Properties.GetValue<Color>("NormalColor"); }
            set { Properties.SetValue("NormalColor", value); }
        }

        /// <summary>
        /// Gets or sets the color used for the button when highlighted.
        /// </summary>
        [XmlElement]
        [Category("Appearance")]
        [EditorBrowsable]
        [Description("Mouseover color.")]
        [Color]
        public Color HighlightColor
        {
            get { return Properties.GetValue<Color>("HighlightColor"); }
            set { Properties.SetValue("HighlightColor", value); }
        }

        /// <summary>
        /// Gets or sets the color used for the button when disabled.
        /// </summary>
        [XmlElement]
        [Category("Appearance")]
        [EditorBrowsable]
        [Description("Define the color to use when a button is disabled.")]
        [Color]
        public Color DisabledColor
        {
            get { return Properties.GetValue<Color>("DisabledColor"); }
            set { Properties.SetValue("DisabledColor", value); }
        }

        /// <summary>
        /// Gets or sets the offset for the text when the button is pushed.
        /// </summary>
        [XmlElement]
        [Category("Appearance")]
        [Description("Text moves when clicked (and held), this defines how far it moves. Text moves back to its previous location when the mouse button is released.")]
        public Dimension PushedTextOffset
        {
            get { return Properties.GetValue<Dimension>("PushedTextOffset"); }
            set { Properties.SetValue("PushedTextOffset", value); }
        }

        /// <summary>
        /// Gets the texture associated with a state of the button.
        /// </summary>
        /// <param name="buttonState">The state of the button.</param>
        /// <returns>An instance of the <see cref="Texture"/> class.</returns>
        public Texture GetStateTexture(ButtonState buttonState)
        {
            switch (buttonState)
            {
                case ButtonState.Normal:
                    return this.NormalTexture;
                case ButtonState.Pushed:
                    return this.PushedTexture;
                case ButtonState.Highlighted:
                    return this.HighlightTexture;
                case ButtonState.Disabled:
                    return this.DisabledTexture;
                default:
                    throw new ArgumentException("Invalid button state.", "buttonState");
            }
        }

        /// <summary>
        /// Gets the font associated with a state of the button.
        /// </summary>
        /// <param name="buttonState">The state of the button.</param>
        /// <returns>An instance of the <see cref="Font"/> class.</returns>
        public ButtonStyle GetStateStyle(ButtonState buttonState)
        {
            switch (buttonState)
            {
                case ButtonState.Normal:
                case ButtonState.Pushed:
                    return this.NormalFont;
                case ButtonState.Highlighted:
                    return this.HighlightFont;
                case ButtonState.Disabled:
                    return this.DisabledFont;
                default:
                    throw new ArgumentException("Invalid button state.", "buttonState");
            }
        }

        /// <summary>
        /// Gets the color associated with a state of the button.
        /// </summary>
        /// <param name="buttonState">The state of the button.</param>
        /// <returns>An instance of the <see cref="Color"/> class.</returns>
        public Color GetStateColor(ButtonState buttonState)
        {
            switch (buttonState)
            {
                case ButtonState.Normal:
                case ButtonState.Pushed:
                    return this.NormalColor;
                case ButtonState.Highlighted:
                    return this.HighlightColor;
                case ButtonState.Disabled:
                    return this.DisabledColor;
                default:
                    throw new ArgumentException("Invalid button state.", "buttonState");
            }
        }

        /// <summary>
        /// Gets a value indicating whether a serialization object is complete and can be rendered.
        /// </summary>
        public override bool IsComplete
        {
            get
            {
                return NormalTexture != null;
            }
        }

        /// <summary>
        /// Determines whether the specified property name is valid.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value.</param>
        /// <returns>
        /// 	<c>true</c> if the specified property name is valid; otherwise, <c>false</c>.
        /// </returns>
        public bool ValidatePoperty(string propertyName, object value)
        {
            if (propertyName == "Alpha")
            {
                float floatValue = (float)value;

                if (floatValue < 0 || floatValue > 1)
                    throw new ArgumentException(String.Format("{0} property must be between 0 and 1.", propertyName));
            }

            return true;
        }
    }
}